package com.lm.ofdrw.utils;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.ofdrw.core.attachment.CT_Attachment;
import org.ofdrw.pkg.container.OFDDir;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ofdrw.converter.ofdconverter.PDFConverter;
import org.ofdrw.reader.OFDReader;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @ClassName: PdfToOfdUtil
 * @Description: pdf转Ofd工具类
 * @Author:     shdxhl
 * @Date:        2023-07-13 17:15
 * @Version: 1.0.
 */
public class OfdUtil {

    protected static final Log logger = LogFactory.getLog(OfdUtil.class);

    public static final String OFD_XML_FORMAT = "XML";

    public static Document getDocument() {
        return document;
    }

    public void setDocument(Document document) {
        this.document = document;
    }

    static Document document;
    /**
     * pdf转Ofd文件 awt  Graphics 2d绘制
     * @Author lisk
     * @Method  convertBy2D
     * @Date 17:38 2023-07-13
     * @Param [resourceFilePath, targetFilePath]
     * @return void
     **/
    public static void convertBy2D(String resourceFilePath, String targetFilePath) throws Exception{
        Path src = Paths.get(resourceFilePath);
        Path dst = Paths.get(targetFilePath);
        try (PDFConverter converter = new PDFConverter(dst)) {
            converter.convert(src);
        }
    }

    public static OFDReader ofdParse(String ofdFilePath) throws Exception{
        Path input = Paths.get(ofdFilePath);
        return  new OFDReader(input);
    }

    public static OFDReader ofdParse(Path input) throws Exception{
        return  new OFDReader(input);
    }

    public static  List<CT_Attachment> getAttachmentList(OFDReader ofdReader){
        return ofdReader.getAttachmentList();
    }

    public static  List<CT_Attachment> getAttachmentList(OFDReader ofdReader, String format){
        List<CT_Attachment> attachmentList = ofdReader.getAttachmentList();
        return attachmentList.stream().filter(x -> x.getFormat().equals(format)).collect(Collectors.toList());
    }

    public static  CT_Attachment getCTAttachment(OFDReader ofdReader,String format){
        List<CT_Attachment> attachmentList = ofdReader.getAttachmentList();
        List<CT_Attachment> ctAttachments = attachmentList.stream().filter(x -> x.getFormat().equals(format)).collect(Collectors.toList());
        if(Objects.nonNull(ctAttachments) && ctAttachments.size() > 0){
            return  ctAttachments.get(0);
        }
        return  null;
    }

    public static void xmlParse(String path)throws Exception{
        Path xmlPath = Paths.get(path);
        SAXReader reader = new SAXReader();
        document = reader.read(xmlPath.toFile());
    }

    public static void xmlParse(InputStream inputStream)throws Exception{
        SAXReader reader = new SAXReader();
        document = reader.read(inputStream);
    }

    public static List<Node> getNodes(String elePath){
        List<Node> extNodes = document.selectNodes(elePath);
        return extNodes;
    }


    public static Object getEleValue( List<Element> nodes , String key){
        for (Element el : nodes){
            if(el.attributeValue("id").equals(key)){
                return el.attributeValue("name");
            }
        }
        return null;
    }

    public static Map<String , Object> checkNodeData(String key, List<Element> dataSource, List<Element> targetMapping){
        Map<String, Object> resultMap = new HashMap<>();
        targetMapping.forEach(x->{
            String value = x.attributeValue(key);
            String requiredStr = x.attributeValue("required");
            if(StringUtils.isNotEmpty(requiredStr) && Boolean.valueOf(requiredStr)){
                List<Element> elements = dataSource.stream().filter(ele -> ele.attributeValue(key).equals(value)).collect(Collectors.toList());
                if(Objects.nonNull(elements) && elements.size()> 0){
                    Element ele = elements.get(0);
                    if(Objects.isNull(ele.getData()) || StringUtils.isEmpty(String.valueOf(ele.getData()))){
                        resultMap.put(value, value + "字段为空");
                    }
                }
            }
        });
        return resultMap;
    }

    public static  void setNodeData(String key, List<Element> dataSource, Map<String, Object> sourseMap){
        sourseMap.entrySet().stream().forEach(entry->{
            String skey = entry.getKey();
            Object sValue = entry.getValue();
            List<Element> elements = dataSource.stream().filter(ele -> ele.attributeValue(key).toLowerCase().equals(skey)).collect(Collectors.toList());
            if(Objects.nonNull(elements) && elements.size()> 0){
                Element ele = elements.get(0);
                if(Objects.nonNull(ele)){
                    ele.setText(String.valueOf(sValue));
                }
            }
        });
    }

    public static Map<String , Object> LoadNodeData(String key, List<Element> dataSource, List<Element> targetMapping){
        Map<String, Object> resultMap = new HashMap<>();
        targetMapping.forEach(x->{
            String value = x.attributeValue(key);
            List<Element> elements = dataSource.stream().filter(ele -> ele.attributeValue(key).equals(value)).collect(Collectors.toList());
            if(Objects.nonNull(elements) && elements.size()> 0){
                Element ele = elements.get(0);
                String data = String.valueOf(ele.getData());
                if(Objects.nonNull(ele.getData()) && StringUtils.isNotEmpty(data)){
                    resultMap.put(value.toLowerCase(), ele.getData());
                }
            }
        });
        return resultMap;
    }

    public static Map<String , Object> LoadNodeDataByName(String key, List<Element> dataSource, List<Element> targetMapping){
        Map<String, Object> resultMap = new HashMap<>();
        targetMapping.forEach(x->{
            String value = x.attributeValue(key);
            String field = x.attributeValue("name");
            List<Element> elements = dataSource.stream().filter(ele -> ele.attributeValue(key).equals(value)).collect(Collectors.toList());
            if(Objects.nonNull(elements) && elements.size()> 0){
                Element ele = elements.get(0);
                resultMap.put(field, ele.getData());
            }
        });
        return resultMap;
    }

    public static  String  getBasePath(OFDReader ofdReader){
        OFDDir ofdDir = ofdReader.getOFDDir();
        return ofdDir.getSysAbsPath();
    }

    public  static  String getAttachmentPath(OFDReader ofdReader, String format){
        String basePath = getBasePath(ofdReader);
        List<CT_Attachment> attachmentList = getAttachmentList(ofdReader, format);
        if(Objects.nonNull(attachmentList) && attachmentList.size() >0){
            CT_Attachment ctAttachment = attachmentList.get(0);
            Path xmlPath = Paths.get(basePath + ctAttachment.getFileLoc().getLoc());
            return xmlPath.toString();
        }
        return basePath;
    }

    public static void jar(Path jarPath, Path targetFilePath) throws IOException {
        OFDDir ofdDir = new OFDDir(jarPath);
        ofdDir.jar(targetFilePath);
    }

    public static void unzipOFD(String inputOfdFilePath, String outputDirectoryPath) throws IOException {
        // 创建输出目录
        Files.createDirectories(Paths.get(outputDirectoryPath));

        try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(inputOfdFilePath))) {
            // 遍历 ZIP 文件中的条目
            ZipEntry zipEntry;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                // 构建输出文件路径
                String outputPath = Paths.get(outputDirectoryPath, zipEntry.getName()).toString();

                Path outPath = Paths.get(outputPath);
                Path parentFolder = outPath.getParent();
                if(parentFolder != null){
                    if(!Files.exists(parentFolder)){
                        Files.createDirectories(parentFolder);
                    }
                }

                // 如果是目录，则创建目录
                if (zipEntry.isDirectory()) {
                    Files.createDirectories(Paths.get(outputPath));
                } else {
                    // 如果是文件，则写入文件内容
                    writeEntryToFile(zipInputStream, outputPath);
                }

                zipInputStream.closeEntry();
            }
        }
    }

    private static void writeEntryToFile(ZipInputStream zipInputStream, String outputPath) throws IOException {
        try (BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputPath))) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = zipInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
    }

    public static void main(String[] args) throws Exception{
        String ofdFilePath = "E:\\0C7AECB3DDF149B3BD10963880AB5586.ofd";
        String xmlFilePath = "E:\\mapping.xml";
        Path input = Paths.get(ofdFilePath);
        OFDReader ofdReader = ofdParse(input);
        String attachmentPath = getAttachmentPath(ofdReader, OFD_XML_FORMAT);

        OfdUtil.xmlParse(attachmentPath);



        File file = new File(attachmentPath);
        System.out.println("file:" + file.getName());

    }

    /**
     * pdf转Ofd文件通过Graphics 流绘制
     * @Author lisk
     * @Method  convert
     * @Date 17:38 2023-07-13
     * @Param [resourceFilePath, targetFilePath]
     * @return void
     **/
    public static void convert(String resourceFilePath, String targetFilePath) throws Exception {
       convertBy2D(resourceFilePath,targetFilePath);
    }


    /**
     *通过pdf byte转ofd byte  awt  Graphics 2d绘制
     * @Author lisk
     * @Method  convertBy2D
     * @Date 17:39 2023-07-13
     * @Param [pdfFile]
     * @return java.io.InputStream
     **/
    public static byte[] convertBy2D(byte[] pdfBytes,String originalPath, String targetPath) throws Exception{
        FileUtils.writeByteArrayToFile(new File(originalPath), pdfBytes);
        if(Objects.nonNull(originalPath)){
            convertBy2D(originalPath, targetPath);
        }
        File targetFile = new File(targetPath);
        if(targetFile.exists()){
            return FileUtils.readFileToByteArray(targetFile);
        }
        return null;
    }
}
